package com.xyy.saas.payment.controller;

import com.alibaba.fastjson.JSON;
import com.jddglobal.open.client.DefaultSpiJddClient;
import com.jddglobal.open.response.base.SpiResponse;
import com.jddglobal.open.support.config.EsuSdkConfig;
import com.jddglobal.open.support.util.JacksonUtils;
import com.xyy.saas.payment.adpater.fumin.config.CertConstants;
import com.xyy.saas.payment.adpater.fumin.config.SDKVersion;
import com.xyy.saas.payment.adpater.jdCredit.enums.CodeEnum;
import com.xyy.saas.payment.adpater.jdCredit.req.QueryOrderReq;
import com.xyy.saas.payment.adpater.jdCredit.resp.ApiResponse;
import com.xyy.saas.payment.adpater.jdCredit.util.DateUtil;
import com.xyy.saas.payment.callback.core.handler.*;
import com.xyy.saas.payment.callback.core.service.CallbackResponseAdapterService;
import com.xyy.saas.payment.callback.core.service.NotifyService;
import com.xyy.saas.payment.callback.core.util.VerifySign;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.query.core.service.QueryTradeService;
import com.xyy.saas.payment.trace.AlarmService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 第三方渠道回调统一入口
 */
@RestController
@RequestMapping(value = {"/platform", "/api/platform"})
public class PlatformController implements InitializingBean {
    private static Logger LOGGER = LoggerFactory.getLogger(PlatformController.class);
    
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private QueryTradeService queryTradeService;
    @Autowired
    private JdCreditContractCallBackHandler jdCreditContractCallBackHandler;
    @Autowired
    private JdCreditPayResultHandler jdCreditPayResultHandler;
    @Autowired
    private VerifySign verifySign;
    @Resource
    private AlarmService alarmService;
    @Resource
    private NotifyService notifyService;
    private Map<String, BaseHandler> method2Map = new HashMap<>();

    private Map<String, CastRequestHandler> castRequestMap = new HashMap<>();


    @RequestMapping(value = "/jd/{ch}/{method}", method = RequestMethod.POST)
    public void jdCallBack(
            @PathVariable("ch") String ch,
            @PathVariable("method") String method,
            HttpServletRequest request,
            HttpServletResponse response) {
        LOGGER.info("jdCallBack begin ch:{}, method:{}", ch, method);

        try {
            //TODO 更换枚举
            if (ch.equals("jdCredit") && method.equals("contractNotice")) {
                jdCreditContractCallBackHandler.callBackHandler(request);
            } else if (ch.equals("jdCredit") && method.equals("payNotice")) {
                jdCreditPayResultHandler.callBackHandler(request);
            } else {
                notifyService.jdCallback(ch, method, request);
            }

            setSuccessResponse(request, response);
        } catch (Exception e) {
            LOGGER.error("jdCallBack error {}",method, e);
            // 还款计划更新接口 可接受重试，幂等，不告警
            if (!"repayNotice".equals(method)) {
                alarmService.asyncAlarm("京东回调接口", "jdCallBack", "接口异常" + e.getMessage(), null);
            }
        }

    }

    private void setSuccessResponse(HttpServletRequest request, HttpServletResponse response) throws Exception {
        DefaultSpiJddClient defaultSpiJddClient = new DefaultSpiJddClient(EsuSdkConfig.getAppInfo());
        //返回参数封装
        ApiResponse apiResponse = new  ApiResponse();
        apiResponse.setReqNo(DateUtil.formatDateString(new Date(), DateUtil.DATEPATTERN));
        apiResponse.setResDate(DateUtil.formatDateString(new Date(), DateUtil.DATEPATTERN));
        //如果有返回数据
        Map<String, Object> res = new HashMap<>();
        apiResponse.setData(res);
        //成功
        apiResponse.setResCode(CodeEnum.SUCCESS.getCode());
        apiResponse.setResDesc(CodeEnum.SUCCESS.getMsg());
        //失败
        //apiResponse.setResCode(CodeEnum.FAIL.getCode());
        //apiResponse.setResDesc(CodeEnum.FAIL.getMsg());
        SpiResponse spiResponse = new SpiResponse("00000", "成功",
                DateUtil.formatDateString(new Date(), DateUtil.DATEPATTERN),
                JacksonUtils.toJson(apiResponse));
        String bodyres = defaultSpiJddClient.callback(request, response, spiResponse);
        LOGGER.info("response,bodyres={}", bodyres);
        //获得字符输出流
        response.setCharacterEncoding("utf-8");
        PrintWriter writer = response.getWriter();
        writer.write(bodyres);
    }

    @RequestMapping(value = "/{ch}/{method}", method = RequestMethod.POST)
    public String chargeCallBack(
            @PathVariable("ch") String ch,
            @PathVariable("method") String method,
            @RequestParam Map<String, String> request,
            @RequestBody String body,
            HttpServletRequest requestMsg,
            HttpServletResponse response) {
        LOGGER.info("PlatformController chargeCallBack begin ch:{}, method:{}, request:{}, body:{}", ch, method, request, body);

        // 此处验证签名
        try {
            if(!verifySign.verifyData(ch, method, requestMsg, body)) {
                return Constants.SIGN_ERROR;
            }
        }
        catch(Exception e) {
            LOGGER.error("PlatformController#verifyData error ch:{}, method:{}, request:{}, body:{}", ch, method, request, body, e);
            return Constants.SIGN_ERROR;
        }

        request.put("post-val", body);
        boolean success = callbackHandler(method, ch, request, requestMsg);

        try {
            String version = SDKVersion.SDK_VERSION;

            if(StringUtils.isNotBlank(body) && body.contains(CertConstants.ALGORITHM_RSAV2)) {
                version = SDKVersion.SDK_VERSION_V2;
            }

            return getResponseMsg(ch, success, response, version);
        }
        catch(Exception e) {
            LOGGER.error("PlatformController#chargeCallBack error ch:{}, method:{}, request:{}, body:{}", ch, method, request, body, e);
            response.setStatus(500);
            return Constants.CHINABANK_CALLBACK_FAIL;
        }
    }

    private boolean callbackHandler(String method, String ch, Map<String, String> request, HttpServletRequest requestMsg) {
        try {
            // 处理核心逻辑的 handler
            BaseHandler base = method2Map.get(method);
            // 转换请求对象 handler
            CastRequestHandler cast = castRequestMap.get(ch);
            Object domain = cast.castRequestHandler(method, request, requestMsg);
            return base.callBackHandler(domain);
        }
        catch(Exception e) {
            LOGGER.error("PlatformController#callbackHandler error method:{} ch:{} request:{}", method, ch, JSON.toJSONString(request), e);
            if(e instanceof PaymentException && ResultCodeEnum.PINGAN_IGNORE_ERROR.getCode().equals(((PaymentException) e).getErrCode())) {
                return true;
            }

            return false;
        }
    }

    private String getResponseMsg(String channel, boolean success, HttpServletResponse response, String version) throws Exception {
       return CallbackResponseAdapterService.getInstance().invoker(channel, success, response, version);
    }
    /**
     * 京东侧请求
     * 查询订单信息-合作方提供
     * @param request  请求
     * @param response
     */
    @PostMapping("/queryOrderInfo")
    public void queryOrderInfo(HttpServletRequest request, HttpServletResponse response){
        try {
            DefaultSpiJddClient defaultSpiJddClient = new DefaultSpiJddClient(EsuSdkConfig.getAppInfo());
            String bizContent = defaultSpiJddClient.receive(request);
            QueryOrderReq queryOrderReq = JSON.parseObject(bizContent, QueryOrderReq.class);
            LOGGER.info("queryOrderInfo queryOrderReq={}", queryOrderReq);

            SpiResponse resp = queryTradeService.queryOrderInfo(queryOrderReq);
            String body = defaultSpiJddClient.callback(request, response, resp);
            LOGGER.info("queryOrderInfo queryOrderReq={},resp:{}", queryOrderReq,resp.getResultParams());
            //获得字符输出流
            response.setCharacterEncoding("utf-8");
            PrintWriter writer = response.getWriter();
            writer.write(body);
        } catch (Exception e) {
            LOGGER.error("queryOrderInfo error",e);
        }
    }
    @Override
    public void afterPropertiesSet() {
        Map<String, BaseHandler> beansOfType = applicationContext.getBeansOfType(BaseHandler.class);
        Map<String, CastRequestHandler> castRequestBeans = applicationContext.getBeansOfType(CastRequestHandler.class);

        for(BaseHandler handler : beansOfType.values()) {
            method2Map.put(handler.getMethod(), handler);
        }

        for(CastRequestHandler handler : castRequestBeans.values()) {
            castRequestMap.put(handler.getChannel(), handler);
        }
    }
}

